package com.gitee.wsl.common.ui.draw.container

import androidx.compose.ui.graphics.Matrix
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.withTransform
import androidx.compose.ui.graphics.vector.DefaultPivotX
import androidx.compose.ui.graphics.vector.DefaultPivotY
import androidx.compose.ui.graphics.vector.DefaultRotation
import androidx.compose.ui.graphics.vector.DefaultScaleX
import androidx.compose.ui.graphics.vector.DefaultScaleY
import androidx.compose.ui.graphics.vector.DefaultTranslationX
import androidx.compose.ui.graphics.vector.DefaultTranslationY
import com.gitee.wsl.common.ui.draw.api.HasChildren
import com.gitee.wsl.common.ui.draw.api.HasTransform
import com.gitee.wsl.common.ui.draw.api.Transform
import com.gitee.wsl.common.ui.draw.node.Node

open class GroupNode : Node(),
    HasChildren,
    HasTransform {
        
    override var transform: Transform? = null

     fun transform(init: Transform.() -> Unit) {
        transform = Transform().apply(init)
    }

     val children: MutableList<Node> = mutableListOf<Node>()

    override fun add(node: Node) {
        children.add(node)
        node.parent = this
    }

    override fun remove(node: Node) {
        node.parent = null
        children.remove(node)
    }

    override fun clear() {
        children.clear()
    }

     private var groupMatrix: Matrix? = null

     private var isMatrixDirty = true

     val numChildren: Int
         get() = children.size

     var rotation: Float = DefaultRotation
         set(value) {
             field = value
             isMatrixDirty = true
             invalidate()
         }

     var pivotX: Float = DefaultPivotX
         set(value) {
             field = value
             isMatrixDirty = true
             invalidate()
         }

     var pivotY: Float = DefaultPivotY
         set(value) {
             field = value
             isMatrixDirty = true
             invalidate()
         }

     var scaleX: Float = DefaultScaleX
         set(value) {
             field = value
             isMatrixDirty = true
             invalidate()
         }

     var scaleY: Float = DefaultScaleY
         set(value) {
             field = value
             isMatrixDirty = true
             invalidate()
         }

     var translationX: Float = DefaultTranslationX
         set(value) {
             field = value
             isMatrixDirty = true
             invalidate()
         }

     var translationY: Float = DefaultTranslationY
         set(value) {
             field = value
             isMatrixDirty = true
             invalidate()
         }

     override var invalidateListener: (() -> Unit)? = null
         set(value) {
             field = value
             children.forEach { child ->
                 child.invalidateListener = value
             }
         }

     fun insertAt(index: Int, instance: Node) {
         if (index < numChildren) {
             children[index] = instance
         } else {
             children.add(instance)
         }
         instance.invalidateListener = invalidateListener
         invalidate()
     }

     fun move(from: Int, to: Int, count: Int) {
         if (from > to) {
             var current = to
             repeat(count) {
                 val node = children[from]
                 children.removeAt(from)
                 children.add(current, node)
                 current++
             }
         } else {
             repeat(count) {
                 val node = children[from]
                 children.removeAt(from)
                 children.add(to - 1, node)
             }
         }
         invalidate()
     }

     fun remove(index: Int, count: Int) {
         repeat(count) {
             if (index < children.size) {
                 children[index].invalidateListener = null
                 children.removeAt(index)
             }
         }
         invalidate()
     }
     
     override fun DrawScope.draw() {
         if (isMatrixDirty) {
             updateMatrix()
             isMatrixDirty = false
         }

         withTransform({
             groupMatrix?.let { transform(it) }
         }) {
             children.forEach { node ->
                 with(node) {
                     this@draw.draw()
                 }
             }
         }
     }

     private fun updateMatrix() {
         val matrix: Matrix
         val target = groupMatrix
         if (target == null) {
             matrix = Matrix()
             groupMatrix = matrix
         } else {
             matrix = target
             matrix.reset()
         }
         matrix.translate(translationX + pivotX, translationY + pivotY)
         matrix.rotateZ(degrees = rotation)
         matrix.scale(scaleX, scaleY, 1f)
         matrix.translate(-pivotX, -pivotY)
     }
 }

fun GroupNode.group(block:GroupNode.(superNode:GroupNode)->Unit){
    val node=GroupNode()
    node.block(this)
    add(node)
}